package own.stu.jobgib.playown.netty.im.client.v2;

import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.concurrent.GenericFutureListener;
import io.netty.util.concurrent.ScheduledFuture;

import java.util.Random;
import java.util.concurrent.TimeUnit;

import static own.stu.jobgib.playown.netty.im.client.v2.Client_v2.HEART_BEAT;

public class Pinger extends ChannelInboundHandlerAdapter {

    private Random random = new Random();
    private int baseRandom = 8;
    private Channel channel;

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        super.channelActive(ctx);
        this.channel = ctx.channel();
        ping(ctx.channel());
    }

    private void ping(Channel channel) {
        int sec = random.nextInt(baseRandom);
        if (sec == 5) {
            sec = 6; // 为了避开 Connection reset by peer 异常
        }
        System.out.println("next heart beat will send after " + sec + "s.");
        ScheduledFuture<?> schedule = channel.eventLoop().schedule(() -> {
            if (channel.isActive()) {
                System.out.println("sending heart beat to the server...");
                channel.writeAndFlush(HEART_BEAT);
            } else {
                System.err.println("The connection had broken, cancel the task that will send a heart beat.");
                channel.closeFuture();
                new RuntimeException();
            }
        }, sec, TimeUnit.SECONDS);
        schedule.addListener((GenericFutureListener) future -> {
            if (future.isSuccess() && channel.isActive()) {
                ping(channel);
            }
        });
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        // 当Channel已经断开的情况下, 仍然发送数据, 会抛异常, 该方法会被调用.
        cause.printStackTrace();
        ctx.close();
    }
}